﻿using System;
using SoftwareConsulting.BI11.NumericalMethods.ComplexNumbers;

namespace SoftwareConsulting.BI11.NumericalMethods.Interpolation
{
    /// <summary>
    /// Класс барицентрической интерполяции
    /// </summary> 
    /// <remarks>    
    /// F(t) = SUM(i=0,n-1,w[i]*f[i]/(t-x[i])) / SUM(i=0,n-1,w[i]/(t-x[i]))
    /// 
    /// Входные параметры:
    /// X   -   абсциссы точек;
    /// F   -   значения функций в этих точках;
    /// W   -   весовые коэффициенты;
    /// N   -   число точек;
    /// T   -   точка, в которой осуществляется интерполяция.
    /// Результат:
    ///     значение барицентрического интерполянта в точке T
    ///</remarks>
    public class BarycentricInterpolation
    {
        private double _result;

        /// <summary>
        /// Конструктор по умолчанию
        /// </summary>                
        public BarycentricInterpolation(double[] x,double[] f,double[] w,int n,double t)
        {
            _result = 0;
            double s1 = 0;
            double s2 = 0;
            double v = 0;
            double threshold = 0;
            double s = 0;
            int i = 0;
            int j = 0;
            threshold = Math.Sqrt(ComplexMath.MinRealNumber);
            //Используем безопасную от переполнений формулу или быструю?                        
            s = t - x[0];
            for (i = 1; i <= n - 1; i++)
            {
                if (Math.Abs(t - x[i]) < Math.Abs(s))
                {
                    s = t - x[i];
                    j = i;
                }
            }
            if (s == 0)
            {
                _result = f[j];
            }
            if (Math.Abs(s) > threshold)
            {
                //быструю
                j = -1;
                s = 1.0;
            }
            //основные вычисления
            s1 = 0;
            s2 = 0;
            for (i = 0; i <= n - 1; i++)
            {
                if (i != j)
                {
                    v = s * w[i] / (t - x[i]);
                    s1 = s1 + v * f[i];
                    s2 = s2 + v;
                    continue;
                }                
                v = w[i];
                s1 = s1 + v * f[i];
                s2 = s2 + v;                
            }
            _result = s1 / s2;
        }

        /// <summary>
        /// Возвращает решение
        /// </summary>        
        public double GetSolution()
        {
            return _result;
        }
    }
}
